# app_control.py
import cv2
import mediapipe as mp
import numpy as np
import tensorflow as tf
from collections import deque
import time
import pyautogui
import os
import tkinter as tk
from tkinter import ttk, messagebox
# from PIL import Image, ImageTk
import threading
import json
# import sys
import atexit
import pystray
from pystray import MenuItem as item
from PIL import Image
import queue

from improved_preprocessing import extract_detailed_features

# 默认配置
DEFAULT_CONFIG = {
    "model_path": "improved_gesture_classifier.keras",
    "sequence_names": ["向下滑动", "向上滑动", "抓取动作"],
    "prepare_frames": 25,
    "movement_threshold": 0.15,
    "confidence_threshold": 0.7,
    "cooldown_duration": 2.0,
    "control_cooldown": 1.5,
    "hud_display_time": 1.0,
    "hud_position": "top_right",
    "hud_opacity": 0.9,
    "startup_with_windows": False,
    "gesture_functions": {
        "向下滑动": "volume_down",
        "向上滑动": "volume_up",
        "抓取动作": "screenshot"
    },
    "hud_display_content": ["gesture_icon", "gesture_name", "confidence", "control_result"],
    "hud_width": 200,
    "hud_height": 100,
}


class ConfigManager:
    """配置管理器"""

    def __init__(self, config_file="gesture_config.json"):
        self.config_file = config_file
        self.config = self.load_config()

    def load_config(self):
        """加载配置"""
        if os.path.exists(self.config_file):
            try:
                with open(self.config_file, 'r', encoding='utf-8') as f:
                    return json.load(f)
            except:
                return DEFAULT_CONFIG.copy()
        return DEFAULT_CONFIG.copy()

    def save_config(self):
        """保存配置"""
        try:
            with open(self.config_file, 'w', encoding='utf-8') as f:
                json.dump(self.config, f, ensure_ascii=False, indent=2)
            return True
        except:
            return False

    def get(self, key, default=None):
        """获取配置值"""
        return self.config.get(key, default)

    def set(self, key, value):
        """设置配置值"""
        self.config[key] = value

    def reset_to_default(self):
        """重置为默认配置"""
        self.config = DEFAULT_CONFIG.copy()
        return self.save_config()


class SettingsWindow:
    """设置窗口 - 独立于悬浮窗"""

    def __init__(self, config_manager, gesture_control):
        self.config_manager = config_manager
        self.gesture_control = gesture_control
        self.setup_window()
        self.create_widgets()
        self.load_current_settings()

    def setup_window(self):
        """设置窗口属性"""
        self.window = tk.Toplevel()
        self.window.title("手势控制设置")
        self.window.geometry("600x700")
        self.window.resizable(True, True)
        self.window.configure(bg='#f0f0f0')

        # 窗口居中显示
        self.window.update_idletasks()
        width = self.window.winfo_width()
        height = self.window.winfo_height()
        x = (self.window.winfo_screenwidth() // 2) - (width // 2)
        y = (self.window.winfo_screenheight() // 2) - (height // 2)
        self.window.geometry(f"{width}x{height}+{x}+{y}")

        # 窗口关闭事件
        self.window.protocol("WM_DELETE_WINDOW", self.cancel_settings)

    def load_model_configs(self):
        """加载模型配置文件"""
        try:
            with open('model_config.json', 'r', encoding='utf-8') as f:
                return json.load(f)
        except Exception as e:
            print(f"加载模型配置失败: {e}")
            return {"models": {}}

    def create_widgets(self):
        """创建控件"""
        # 创建笔记本（选项卡）
        notebook = ttk.Notebook(self.window)
        notebook.pack(fill='both', expand=True, padx=10, pady=10)

        # 基本设置标签页
        basic_frame = ttk.Frame(notebook, padding=10)
        notebook.add(basic_frame, text="基本设置")

        # 模型选择 - 动态加载模型列表
        ttk.Label(basic_frame, text="模型选择:").grid(row=0, column=0, sticky='w', pady=5)
        self.model_var = tk.StringVar()
        model_combo = ttk.Combobox(basic_frame, textvariable=self.model_var, state="readonly")

        # 自动读取配置文件中的模型列表
        model_configs = self.load_model_configs()
        model_names = list(model_configs["models"].keys())
        model_combo['values'] = tuple(model_names) if model_names else ('improved_gesture_classifier.keras',)

        model_combo.grid(row=0, column=1, sticky='ew', pady=5, padx=5)

        # 起始手势判断时间
        ttk.Label(basic_frame, text="起始手势判断时间(帧):").grid(row=1, column=0, sticky='w', pady=5)
        self.prepare_frames_var = tk.IntVar()
        prepare_frames_scale = ttk.Scale(basic_frame, from_=10, to=50, variable=self.prepare_frames_var,
                                         orient='horizontal')
        prepare_frames_scale.grid(row=1, column=1, sticky='ew', pady=5, padx=5)
        self.prepare_frames_label = ttk.Label(basic_frame, text="25")
        self.prepare_frames_label.grid(row=1, column=2, pady=5, padx=5)

        # 手势识别置信度阈值
        ttk.Label(basic_frame, text="置信度阈值:").grid(row=2, column=0, sticky='w', pady=5)
        self.confidence_var = tk.DoubleVar()
        confidence_scale = ttk.Scale(basic_frame, from_=0.1, to=1.0, variable=self.confidence_var, orient='horizontal')
        confidence_scale.grid(row=2, column=1, sticky='ew', pady=5, padx=5)
        self.confidence_label = ttk.Label(basic_frame, text="0.70")
        self.confidence_label.grid(row=2, column=2, pady=5, padx=5)

        # 冷却时间
        ttk.Label(basic_frame, text="手势冷却时间(秒):").grid(row=3, column=0, sticky='w', pady=5)
        self.cooldown_var = tk.DoubleVar()
        cooldown_scale = ttk.Scale(basic_frame, from_=0.5, to=5.0, variable=self.cooldown_var, orient='horizontal')
        cooldown_scale.grid(row=3, column=1, sticky='ew', pady=5, padx=5)
        self.cooldown_label = ttk.Label(basic_frame, text="2.0")
        self.cooldown_label.grid(row=3, column=2, pady=5, padx=5)

        # 控制冷却时间
        ttk.Label(basic_frame, text="控制冷却时间(秒):").grid(row=4, column=0, sticky='w', pady=5)
        self.control_cooldown_var = tk.DoubleVar()
        control_cooldown_scale = ttk.Scale(basic_frame, from_=0.5, to=5.0, variable=self.control_cooldown_var,
                                           orient='horizontal')
        control_cooldown_scale.grid(row=4, column=1, sticky='ew', pady=5, padx=5)
        self.control_cooldown_label = ttk.Label(basic_frame, text="1.5")
        self.control_cooldown_label.grid(row=4, column=2, pady=5, padx=5)

        # 绑定滑块事件
        prepare_frames_scale.configure(command=self.update_prepare_frames_label)
        confidence_scale.configure(command=self.update_confidence_label)
        cooldown_scale.configure(command=self.update_cooldown_label)
        control_cooldown_scale.configure(command=self.update_control_cooldown_label)

        # 悬浮窗设置标签页
        hud_frame = ttk.Frame(notebook, padding=10)
        notebook.add(hud_frame, text="悬浮窗设置")

        # 悬浮窗宽度
        ttk.Label(hud_frame, text="悬浮窗宽度:").grid(row=4, column=0, sticky='w', pady=5)
        self.hud_width_var = tk.IntVar()
        hud_width_scale = ttk.Scale(hud_frame, from_=150, to=800, variable=self.hud_width_var, orient='horizontal')
        hud_width_scale.grid(row=4, column=1, sticky='ew', pady=5, padx=5)
        self.hud_width_label = ttk.Label(hud_frame, text="200")
        self.hud_width_label.grid(row=4, column=2, pady=5, padx=5)

        # 悬浮窗高度
        ttk.Label(hud_frame, text="悬浮窗高度:").grid(row=5, column=0, sticky='w', pady=5)
        self.hud_height_var = tk.IntVar()
        hud_height_scale = ttk.Scale(hud_frame, from_=80, to=200, variable=self.hud_height_var, orient='horizontal')
        hud_height_scale.grid(row=5, column=1, sticky='ew', pady=5, padx=5)
        self.hud_height_label = ttk.Label(hud_frame, text="100")
        self.hud_height_label.grid(row=5, column=2, pady=5, padx=5)

        # 绑定滑块事件
        hud_width_scale.configure(command=self.update_hud_width_label)
        hud_height_scale.configure(command=self.update_hud_height_label)


        # 悬浮窗显示位置
        ttk.Label(hud_frame, text="显示位置:").grid(row=0, column=0, sticky='w', pady=5)
        self.hud_position_var = tk.StringVar()
        position_combo = ttk.Combobox(hud_frame, textvariable=self.hud_position_var, state="readonly")
        position_combo['values'] = ('top_left', 'top_right', 'bottom_left', 'bottom_right', 'center_top',
                                    'center_bottom')
        position_combo.grid(row=0, column=1, sticky='ew', pady=5, padx=5)

        # 悬浮窗透明度
        ttk.Label(hud_frame, text="透明度:").grid(row=1, column=0, sticky='w', pady=5)
        self.opacity_var = tk.DoubleVar()
        opacity_scale = ttk.Scale(hud_frame, from_=0.1, to=1.0, variable=self.opacity_var, orient='horizontal')
        opacity_scale.grid(row=1, column=1, sticky='ew', pady=5, padx=5)
        self.opacity_label = ttk.Label(hud_frame, text="0.9")
        self.opacity_label.grid(row=1, column=2, pady=5, padx=5)

        # 悬浮窗显示时间
        ttk.Label(hud_frame, text="显示时间(秒):").grid(row=2, column=0, sticky='w', pady=5)
        self.hud_display_var = tk.DoubleVar()
        display_scale = ttk.Scale(hud_frame, from_=0.5, to=5.0, variable=self.hud_display_var, orient='horizontal')
        display_scale.grid(row=2, column=1, sticky='ew', pady=5, padx=5)
        self.display_label = ttk.Label(hud_frame, text="1.0")
        self.display_label.grid(row=2, column=2, pady=5, padx=5)

        # 显示内容选择
        ttk.Label(hud_frame, text="显示内容:").grid(row=3, column=0, sticky='w', pady=5)
        display_content_frame = ttk.Frame(hud_frame)
        display_content_frame.grid(row=3, column=1, columnspan=2, sticky='w', pady=5)

        self.display_vars = {
            "gesture_icon": tk.BooleanVar(),
            "gesture_name": tk.BooleanVar(),
            "confidence": tk.BooleanVar(),
            "control_result": tk.BooleanVar()
        }

        ttk.Checkbutton(display_content_frame, text="手势图标", variable=self.display_vars["gesture_icon"]).pack(
            anchor='w')
        ttk.Checkbutton(display_content_frame, text="手势名称", variable=self.display_vars["gesture_name"]).pack(
            anchor='w')
        ttk.Checkbutton(display_content_frame, text="置信度", variable=self.display_vars["confidence"]).pack(anchor='w')
        ttk.Checkbutton(display_content_frame, text="控制结果", variable=self.display_vars["control_result"]).pack(
            anchor='w')

        # 绑定滑块事件
        opacity_scale.configure(command=self.update_opacity_label)
        display_scale.configure(command=self.update_display_label)

        # 手势功能设置标签页
        gesture_frame = ttk.Frame(notebook, padding=10)
        notebook.add(gesture_frame, text="手势功能")

        # 手势功能映射
        ttk.Label(gesture_frame, text="手势功能映射:").grid(row=0, column=0, columnspan=3, sticky='w', pady=5)

        self.gesture_vars = {}
        gesture_functions = ["volume_down", "volume_up", "screenshot", "play_pause", "next_track", "previous_track",
                             "mute", "minimize_all"]

        for i, gesture in enumerate(DEFAULT_CONFIG["sequence_names"]):
            ttk.Label(gesture_frame, text=gesture + ":").grid(row=i + 1, column=0, sticky='w', pady=2)
            self.gesture_vars[gesture] = tk.StringVar()
            gesture_combo = ttk.Combobox(gesture_frame, textvariable=self.gesture_vars[gesture],
                                         values=gesture_functions, state="readonly")
            gesture_combo.grid(row=i + 1, column=1, sticky='ew', pady=2, padx=5)

        # 系统设置标签页
        system_frame = ttk.Frame(notebook, padding=10)
        notebook.add(system_frame, text="系统设置")

        # 开机启动
        self.startup_var = tk.BooleanVar()
        ttk.Checkbutton(system_frame, text="开机启动", variable=self.startup_var).grid(row=0, column=0, sticky='w',
                                                                                       pady=5)

        # 按钮框架
        button_frame = ttk.Frame(self.window)
        button_frame.pack(fill='x', padx=10, pady=10)

        # 按钮
        ttk.Button(button_frame, text="恢复默认", command=self.reset_to_default).pack(side='left', padx=5)
        ttk.Button(button_frame, text="应用", command=self.apply_settings).pack(side='left', padx=5)
        ttk.Button(button_frame, text="确定", command=self.ok_settings).pack(side='left', padx=5)
        ttk.Button(button_frame, text="取消", command=self.cancel_settings).pack(side='left', padx=5)

    def update_prepare_frames_label(self, value):
        """更新准备帧数标签"""
        self.prepare_frames_label.config(text=str(int(float(value))))

    def update_confidence_label(self, value):
        """更新置信度标签"""
        self.confidence_label.config(text=f"{float(value):.2f}")

    def update_cooldown_label(self, value):
        """更新冷却时间标签"""
        self.cooldown_label.config(text=f"{float(value):.1f}")

    def update_control_cooldown_label(self, value):
        """更新控制冷却时间标签"""
        self.control_cooldown_label.config(text=f"{float(value):.1f}")

    def update_hud_width_label(self, value):
        """更新悬浮窗宽度标签"""
        self.hud_width_label.config(text=str(int(float(value))))

    def update_hud_height_label(self, value):
        """更新悬浮窗高度标签"""
        self.hud_height_label.config(text=str(int(float(value))))

    def update_opacity_label(self, value):
        """更新透明度标签"""
        self.opacity_label.config(text=f"{float(value):.1f}")

    def update_display_label(self, value):
        """更新显示时间标签"""
        self.display_label.config(text=f"{float(value):.1f}")

    def load_current_settings(self):
        """加载当前设置"""
        config = self.config_manager.config

        # 基本设置
        self.model_var.set(config.get("model_path", DEFAULT_CONFIG["model_path"]))
        self.prepare_frames_var.set(config.get("prepare_frames", DEFAULT_CONFIG["prepare_frames"]))
        self.confidence_var.set(config.get("confidence_threshold", DEFAULT_CONFIG["confidence_threshold"]))
        self.cooldown_var.set(config.get("cooldown_duration", DEFAULT_CONFIG["cooldown_duration"]))
        self.control_cooldown_var.set(config.get("control_cooldown", DEFAULT_CONFIG["control_cooldown"]))

        # 更新标签
        self.update_prepare_frames_label(self.prepare_frames_var.get())
        self.update_confidence_label(self.confidence_var.get())
        self.update_cooldown_label(self.cooldown_var.get())
        self.update_control_cooldown_label(self.control_cooldown_var.get())

        # 悬浮窗大小设置
        self.hud_width_var.set(config.get("hud_width", 200))
        self.hud_height_var.set(config.get("hud_height", 100))

        # 更新标签
        self.update_hud_width_label(self.hud_width_var.get())
        self.update_hud_height_label(self.hud_height_var.get())

        # 悬浮窗设置
        self.hud_position_var.set(config.get("hud_position", DEFAULT_CONFIG["hud_position"]))
        self.opacity_var.set(config.get("hud_opacity", DEFAULT_CONFIG["hud_opacity"]))
        self.hud_display_var.set(config.get("hud_display_time", DEFAULT_CONFIG["hud_display_time"]))

        # 更新标签
        self.update_opacity_label(self.opacity_var.get())
        self.update_display_label(self.hud_display_var.get())

        # 显示内容
        display_content = config.get("hud_display_content", DEFAULT_CONFIG["hud_display_content"])
        for key, var in self.display_vars.items():
            var.set(key in display_content)

        # 手势功能
        gesture_functions = config.get("gesture_functions", DEFAULT_CONFIG["gesture_functions"])
        for gesture, func in gesture_functions.items():
            if gesture in self.gesture_vars:
                self.gesture_vars[gesture].set(func)

        # 系统设置
        self.startup_var.set(config.get("startup_with_windows", DEFAULT_CONFIG["startup_with_windows"]))

    def collect_settings(self):
        """收集设置"""
        settings = {}

        # 基本设置
        settings["model_path"] = self.model_var.get()
        settings["prepare_frames"] = self.prepare_frames_var.get()
        settings["confidence_threshold"] = self.confidence_var.get()
        settings["cooldown_duration"] = self.cooldown_var.get()
        settings["control_cooldown"] = self.control_cooldown_var.get()

        # 悬浮窗大小设置
        settings["hud_width"] = self.hud_width_var.get()
        settings["hud_height"] = self.hud_height_var.get()

        # 悬浮窗设置
        settings["hud_position"] = self.hud_position_var.get()
        settings["hud_opacity"] = self.opacity_var.get()
        settings["hud_display_time"] = self.hud_display_var.get()

        # 显示内容
        settings["hud_display_content"] = [
            key for key, var in self.display_vars.items() if var.get()
        ]

        # 手势功能
        settings["gesture_functions"] = {
            gesture: var.get() for gesture, var in self.gesture_vars.items()
        }

        # 系统设置
        settings["startup_with_windows"] = self.startup_var.get()

        return settings

    def apply_settings(self):
        """应用设置"""
        try:
            settings = self.collect_settings()

            # 更新配置管理器
            for key, value in settings.items():
                self.config_manager.set(key, value)

            # 保存配置
            if self.config_manager.save_config():
                # 更新手势控制系统
                self.gesture_control.update_from_config(self.config_manager.config)
                messagebox.showinfo("成功", "设置已应用成功！")
            else:
                messagebox.showerror("错误", "保存设置失败！")

        except Exception as e:
            messagebox.showerror("错误", f"应用设置时出错：{str(e)}")

    def ok_settings(self):
        """确定设置"""
        self.apply_settings()
        self.window.destroy()

    def cancel_settings(self):
        """取消设置"""
        self.window.destroy()

    def reset_to_default(self):
        """重置为默认设置"""
        if messagebox.askyesno("确认", "确定要恢复默认设置吗？"):
            self.config_manager.reset_to_default()
            self.load_current_settings()
            messagebox.showinfo("成功", "已恢复默认设置！")


class GestureHUD:
    """手势识别悬浮提示窗口 - 仅用于显示手势状态"""

    def __init__(self, config_manager):
        self.config_manager = config_manager
        self.root = None
        self.label = None
        self.setup_gui()

    def setup_gui(self):
        """设置GUI界面"""
        # 创建主提示窗口
        self.root = tk.Toplevel()
        self.root.title("手势提示")
        self.root.overrideredirect(True)  # 无边框
        self.root.attributes('-topmost', True)  # 始终置顶

        # 从配置获取设置
        opacity = self.config_manager.get("hud_opacity", 0.9)
        self.root.attributes('-alpha', opacity)
        self.root.configure(bg='black')

        # 设置窗口位置
        self.update_position()

        # 创建标签
        self.label = tk.Label(
            self.root,
            text="等待手势...",
            font=("Arial", 16, "bold"),
            fg='white',
            bg='black',
            justify=tk.CENTER
        )
        self.label.pack(expand=True, fill=tk.BOTH)

        # 初始隐藏
        self.root.withdraw()

    def update_position(self):
        """更新窗口位置"""
        position = self.config_manager.get("hud_position", "top_right")
        screen_width = self.root.winfo_screenwidth()
        screen_height = self.root.winfo_screenheight()

        # 获取配置的宽度和高度
        hud_width = self.config_manager.get("hud_width", 200)
        hud_height = self.config_manager.get("hud_height", 100)

        if position == "top_left":
            self.root.geometry(f'{hud_width}x{hud_height}+20+20')
        elif position == "top_right":
            self.root.geometry(f'{hud_width}x{hud_height}+{screen_width - hud_width - 20}+20')
        elif position == "bottom_left":
            self.root.geometry(f'{hud_width}x{hud_height}+20+{screen_height - hud_height - 120}')
        elif position == "bottom_right":
            self.root.geometry(
                f'{hud_width}x{hud_height}+{screen_width - hud_width - 20}+{screen_height - hud_height - 120}')
        elif position == "center_top":
            self.root.geometry(f'{hud_width}x{hud_height}+{screen_width // 2 - hud_width // 2}+20')
        elif position == "center_bottom":
            self.root.geometry(
                f'{hud_width}x{hud_height}+{screen_width // 2 - hud_width // 2}+{screen_height - hud_height - 120}')

    def update_from_config(self, config):
        """从配置更新"""
        # 更新透明度
        opacity = config.get("hud_opacity", 0.9)
        self.root.attributes('-alpha', opacity)

        # 更新位置
        self.update_position()

    def show_gesture_status(self, gesture_type, gesture_name="", confidence=0.0, status_text=""):
        """显示手势状态"""
        icons = {
            "palm_up": "🖐️",
            "palm_down": "👇",
            "grab": "✊",
            "success": "✅",
            "preparing": "⏳",
            "ready": "✅",
            "executing": "🎯"
        }

        display_content = self.config_manager.get("hud_display_content", ["gesture_icon", "gesture_name"])

        display_text = ""

        if "gesture_icon" in display_content and gesture_type in icons:
            display_text += icons[gesture_type] + " "

        if "gesture_name" in display_content and gesture_name:
            display_text += gesture_name + " "

        if "confidence" in display_content and confidence > 0:
            display_text += f"({confidence:.3f}) "

        if status_text:
            display_text += f"\n{status_text}"

        if display_text.strip():
            self.label.config(text=display_text.strip())
            self.root.deiconify()  # 显示窗口

    def show_screenshot_effect(self):
        """显示截屏动画效果"""
        # 创建全屏截屏效果窗口
        self.screenshot_window = tk.Toplevel(self.root)
        self.screenshot_window.attributes('-fullscreen', True)
        self.screenshot_window.attributes('-topmost', True)
        self.screenshot_window.attributes('-alpha', 0.0)  # 初始透明
        self.screenshot_window.configure(bg='white')
        self.screenshot_window.overrideredirect(True)

        # 添加截屏图标和文字
        frame = tk.Frame(self.screenshot_window, bg='white')
        frame.place(relx=0.5, rely=0.5, anchor=tk.CENTER)

        icon_label = tk.Label(
            frame,
            text="📸",
            font=("Arial", 80),
            bg='white'
        )
        icon_label.pack()

        text_label = tk.Label(
            frame,
            text="截图已保存",
            font=("Arial", 24, "bold"),
            bg='white'
        )
        text_label.pack()

        # 动画效果
        self.animate_screenshot()

    def animate_screenshot(self):
        """截屏动画"""
        # 白色闪光效果
        for alpha in [0.3, 0.6, 0.9, 0.6, 0.3, 0.0]:
            self.screenshot_window.attributes('-alpha', alpha)
            self.screenshot_window.update()
            time.sleep(0.05)

        # 显示成功提示
        self.screenshot_window.attributes('-alpha', 0.8)
        time.sleep(0.5)

        # 淡出
        for alpha in [0.8, 0.6, 0.4, 0.2, 0.0]:
            self.screenshot_window.attributes('-alpha', alpha)
            self.screenshot_window.update()
            time.sleep(0.1)

        self.screenshot_window.destroy()
        self.screenshot_window = None

    def hide(self):
        """隐藏悬浮窗"""
        self.root.withdraw()

    def update(self):
        """更新GUI"""
        try:
            self.root.update()
        except Exception as e:
            print(f"悬浮窗更新失败: {e}")


class SystemTrayManager:
    """系统托盘管理器"""

    def __init__(self, gesture_control):
        self.gesture_control = gesture_control
        self.tray_icon = None
        self.command_queue = queue.Queue()
        self.setup_tray_icon()

    def setup_tray_icon(self):
        """设置系统托盘图标"""
        try:
            # 创建托盘图标
            image = Image.new('RGB', (64, 64), color='blue')

            # 创建菜单
            menu = (
                item('显示设置', self.on_show_settings),
                item('显示/隐藏悬浮窗', self.on_toggle_hud),
                item('退出', self.on_quit)
            )

            self.tray_icon = pystray.Icon("gesture_control", image, "手势控制", menu)

            # 在单独线程中运行托盘图标
            tray_thread = threading.Thread(target=self.tray_icon.run, daemon=True)
            tray_thread.start()

        except Exception as e:
            print(f"系统托盘图标创建失败: {e}")

    def on_show_settings(self, icon, item):
        """托盘菜单 - 显示设置"""
        self.command_queue.put("show_settings")

    def on_toggle_hud(self, icon, item):
        """托盘菜单 - 切换悬浮窗显示"""
        self.command_queue.put("toggle_hud")

    def on_quit(self, icon, item):
        """托盘菜单 - 退出程序"""
        self.command_queue.put("quit")

    def process_commands(self):
        """处理命令队列"""
        try:
            while True:
                try:
                    # 非阻塞获取命令
                    command = self.command_queue.get_nowait()
                    if command == "show_settings":
                        self.gesture_control.show_settings()
                    elif command == "toggle_hud":
                        self.gesture_control.toggle_hud()
                    elif command == "quit":
                        self.gesture_control.quit_application()
                        break
                except queue.Empty:
                    break
        except Exception as e:
            print(f"处理命令时出错: {e}")

        # 继续处理命令
        if hasattr(self.gesture_control, 'root') and self.gesture_control.root.winfo_exists():
            self.gesture_control.root.after(100, self.process_commands)

    def stop(self):
        """停止托盘图标"""
        if self.tray_icon:
            self.tray_icon.stop()


class SystemGestureControl:
    def __init__(self, config_manager):
        self.config_manager = config_manager

        # 手势识别状态
        self.state = "IDLE"
        self.buffer = deque(maxlen=15)
        self.stable_count = 0
        self.start_pose = None
        self.last_recognition_time = 0
        self.recognition_count = 0
        self.running = True

        # 创建隐藏的主窗口
        self.root = tk.Tk()
        self.root.withdraw()  # 完全隐藏主窗口
        self.root.title("手势控制后台")  # 设置一个有意义的标题

        # 手势悬浮窗
        self.hud = GestureHUD(config_manager)

        # 系统托盘管理器
        self.tray_manager = SystemTrayManager(self)

        # 设置窗口引用
        self.settings_window = None

        # 控制功能状态
        self.control_enabled = True
        self.last_control_time = 0

        # 创建截图目录
        self.screenshot_dir = "screenshots"
        if not os.path.exists(self.screenshot_dir):
            os.makedirs(self.screenshot_dir)

        # 从配置加载参数
        self.update_from_config(config_manager.config)

        # 加载模型
        self.load_model()

        # 开始处理命令队列
        self.tray_manager.process_commands()

    def stop_all(self):
        """停止所有线程"""
        self.running = False
        self.tray_manager.stop()

    def load_model(self):
        """加载模型及其对应的预处理配置"""
        try:
            model_path = self.config_manager.get("model_path", "improved_gesture_classifier.keras")
            self.model = tf.keras.models.load_model(model_path)

            # 读取模型对应的预处理配置
            model_configs = self.load_model_configs()
            model_config = model_configs["models"].get(model_path)

            if model_config and "preprocessing" in model_config:
                scaler_file = model_config["preprocessing"]["scaler_file"]
                self.scaler_params = np.load(scaler_file, allow_pickle=True).item()
            else:
                # 默认使用改进模型的参数
                scaler_file = 'improved_scaler_params.npy'
                self.scaler_params = np.load(scaler_file, allow_pickle=True).item()

            print(f"模型加载成功: {model_path}")
        except Exception as e:
            print(f"模型加载失败: {e}")
            self.model = None

    def load_model_configs(self):
        """加载模型配置文件"""
        try:
            with open('model_config.json', 'r', encoding='utf-8') as f:
                return json.load(f)
        except Exception as e:
            print(f"加载模型配置失败: {e}")
            return {"models": {}}

    def update_from_config(self, config):
        """从配置更新参数"""
        self.prepare_frames = config.get("prepare_frames", 25)
        self.movement_threshold = config.get("movement_threshold", 0.15)
        self.confidence_threshold = config.get("confidence_threshold", 0.7)
        self.cooldown_duration = config.get("cooldown_duration", 2.0)
        self.control_cooldown = config.get("control_cooldown", 1.5)
        self.hud_display_time = config.get("hud_display_time", 1.0)
        self.sequence_names = config.get("sequence_names", ["向下滑动", "向上滑动", "抓取动作"])
        self.gesture_functions = config.get("gesture_functions", {
            "向下滑动": "volume_down",
            "向上滑动": "volume_up",
            "抓取动作": "screenshot"
        })

        # 更新悬浮窗设置
        self.hud.update_from_config(config)

        # 重新加载模型以应用新设置
        self.load_model()

    def extract_features(self):
        """根据当前模型配置动态提取特征"""
        model_path = self.config_manager.get("model_path", "improved_gesture_classifier.keras")

        # 获取模型配置
        model_configs = self.load_model_configs()
        model_config = model_configs["models"].get(model_path)

        if not model_config:
            raise ValueError(f"未找到模型配置: {model_path}")

        # 根据配置选择特征提取方法
        preprocessing_config = model_config["preprocessing"]
        input_dim = preprocessing_config["input_dim"]
        module_name = preprocessing_config["module"]
        function_name = preprocessing_config["function"]

        if len(self.buffer) < 2:
            return np.zeros(input_dim)

        sequence_data = np.array(list(self.buffer))

        # 动态导入模块并调用特征提取函数
        import importlib
        try:
            module = importlib.import_module(module_name)
            extract_function = getattr(module, function_name)
            return extract_function(sequence_data)
        except (ImportError, AttributeError) as e:
            raise ValueError(f"无法导入或调用特征提取函数 {module_name}.{function_name}: {e}")

    def detect_pose(self, landmarks):
        """检测手部姿势"""
        wrist_y = landmarks[1]
        index_tip_y = landmarks[25]
        middle_tip_y = landmarks[37]
        pinky_tip_y = landmarks[61]

        avg_finger_y = (index_tip_y + middle_tip_y + pinky_tip_y) / 3

        if avg_finger_y < wrist_y - 0.15:
            return "fingers_up"
        elif avg_finger_y > wrist_y + 0.15:
            return "fingers_down"
        return "other"

    def execute_control(self, gesture_id):
        """执行控制功能"""
        current_time = time.time()

        # 检查控制冷却时间
        if current_time - self.last_control_time < self.control_cooldown:
            return f"控制功能冷却中... ({self.control_cooldown - (current_time - self.last_control_time):.1f}秒)"

        self.last_control_time = current_time

        if not self.control_enabled:
            return "控制功能已禁用"

        gesture_name = self.sequence_names[gesture_id]
        function_name = self.gesture_functions.get(gesture_name, "")

        try:
            if function_name == "volume_down":
                pyautogui.press('volumedown')
                return "🔉 音量减小"
            elif function_name == "volume_up":
                pyautogui.press('volumeup')
                return "🔊 音量增大"
            elif function_name == "screenshot":
                # 临时隐藏悬浮窗
                self.hud.hide()

                # 等待一小段时间确保悬浮窗已经完全隐藏
                time.sleep(0.1)
                # 生成带时间戳的文件名
                timestamp = time.strftime("%Y%m%d_%H%M%S")
                screenshot_path = f"{self.screenshot_dir}/screenshot_{timestamp}.png"

                # 截屏
                screenshot = pyautogui.screenshot()
                screenshot.save(screenshot_path)

                # 显示截屏动画效果
                self.hud.show_screenshot_effect()

                # 截图完成后显示悬浮窗
                self.hud.show_gesture_status("success", gesture_name, 0, f"📸 截图已保存: {screenshot_path}")

                # 根据配置的时间后隐藏成功提示
                def hide_success():
                    time.sleep(self.hud_display_time)
                    self.hud.hide()

                threading.Thread(target=hide_success, daemon=True).start()

                return f"📸 截图已保存"  # return f"📸 截图已保存:\n {screenshot_path}"

            elif function_name == "play_pause":
                pyautogui.press('playpause')
                return "⏯️ 播放/暂停"
            elif function_name == "next_track":
                pyautogui.press('nexttrack')
                return "⏭️ 下一曲"
            elif function_name == "previous_track":
                pyautogui.press('prevtrack')
                return "⏮️ 上一曲"
            elif function_name == "mute":
                pyautogui.press('volumemute')
                return "🔇 静音"
            elif function_name == "minimize_all":
                pyautogui.hotkey('win', 'd')
                return "⬇️ 最小化所有窗口"
            else:
                return f"❓ 未知功能: {function_name}"
        except Exception as e:
            return f"❌ 控制失败: {str(e)}"

    def toggle_control(self):
        """切换控制功能开关"""
        self.control_enabled = not self.control_enabled
        status = "启用" if self.control_enabled else "禁用"
        return f"🔄 控制功能已{status}"

    def process_frame(self, landmarks):
        if not self.running:
            return None

        current_time = time.time()
        current_pose = self.detect_pose(landmarks)

        # 更新手势悬浮窗
        if self.state == "IDLE":
            self.hud.hide()

        elif self.state == "PREPARING":
            if self.start_pose == "fingers_up":
                self.hud.show_gesture_status("palm_up", "手指朝上", 0,
                                             f"准备中... {min(100, int(self.stable_count / self.prepare_frames * 100))}%")
            elif self.start_pose == "fingers_down":
                self.hud.show_gesture_status("palm_down", "手指朝下", 0,
                                             f"准备中... {min(100, int(self.stable_count / self.prepare_frames * 100))}%")

        elif self.state == "READY":
            if self.start_pose == "fingers_up":
                self.hud.show_gesture_status("ready", "手指朝上", 0, "✓ 姿势稳定！请开始执行动作...")
            elif self.start_pose == "fingers_down":
                self.hud.show_gesture_status("ready", "手指朝下", 0, "✓ 姿势稳定！请开始执行动作...")

        elif self.state == "EXECUTING":
            self.hud.show_gesture_status("executing", "", 0, "检测到动作开始，正在记录...")

        elif self.state == "COOLDOWN":
            if current_time - self.last_recognition_time > self.cooldown_duration:
                self.state = "IDLE"
                return "冷却结束，可以开始新的手势识别"
            return None

        if self.state == "IDLE":
            if current_pose in ["fingers_up", "fingers_down"]:
                self.state = "PREPARING"
                self.start_pose = current_pose
                self.stable_count = 1
                self.buffer.clear()
                return f"检测到{current_pose}姿势，请保持稳定..."

        elif self.state == "PREPARING":
            if current_pose == self.start_pose:
                self.stable_count += 1

                if self.stable_count % 10 == 0:
                    progress = min(100, int(self.stable_count / self.prepare_frames * 100))
                    return f"准备中... {progress}%"

                if self.stable_count >= self.prepare_frames:
                    self.state = "READY"
                    self.buffer.clear()
                    return "✓ 姿势稳定！请开始执行动作..."
            else:
                self.state = "IDLE"
                return "姿势变化，已重置"

        elif self.state == "READY":
            self.buffer.append(landmarks)

            if len(self.buffer) >= 3:
                start_frame = self.buffer[0]
                current_frame = self.buffer[-1]
                movement = np.linalg.norm(current_frame - start_frame)

                if movement > self.movement_threshold:
                    self.state = "EXECUTING"
                    return "检测到动作开始，正在记录..."

        elif self.state == "EXECUTING":
            self.buffer.append(landmarks)

            if len(self.buffer) >= 8:
                recent_frames = list(self.buffer)[-4:]
                recent_movements = []

                for i in range(1, len(recent_frames)):
                    movement = np.linalg.norm(recent_frames[i] - recent_frames[i - 1])
                    recent_movements.append(movement)

                avg_recent_movement = np.mean(recent_movements) if recent_movements else 0

                if avg_recent_movement < self.movement_threshold / 3:
                    if self.model is None:
                        return "❌ 模型未加载，无法识别手势"

                    features = self.extract_features()
                    features_scaled = (features - self.scaler_params['mean']) / self.scaler_params['scale']

                    prediction = self.model.predict(features_scaled.reshape(1, -1), verbose=0)
                    predicted_class = np.argmax(prediction)
                    confidence = np.max(prediction)

                    self.recognition_count += 1
                    self.last_recognition_time = time.time()

                    gesture_name = self.sequence_names[predicted_class]
                    control_result = ""

                    result = f"🎯 识别: {gesture_name} (置信度: {confidence:.3f})"

                    if self.control_enabled and confidence > self.confidence_threshold:
                        control_result = self.execute_control(predicted_class)
                        result += f"\n   {control_result}"

                    # 显示识别成功提示
                    self.hud.show_gesture_status("success", gesture_name, confidence, control_result)

                    self.state = "COOLDOWN"

                    # 根据配置的时间后隐藏成功提示
                    def hide_success():
                        time.sleep(self.hud_display_time)
                        self.hud.hide()

                    threading.Thread(target=hide_success, daemon=True).start()

                    return result

        return None

    def show_settings(self):
        """显示设置窗口"""
        try:
            # 检查是否已经有设置窗口存在
            if self.settings_window and hasattr(self.settings_window,
                                                'window') and self.settings_window.window.winfo_exists():
                # 如果窗口存在，将其提到前面
                self.settings_window.window.lift()
                self.settings_window.window.focus_force()
            else:
                # 创建新的设置窗口
                self.settings_window = SettingsWindow(self.config_manager, self)
        except Exception as e:
            print(f"打开设置窗口失败: {e}")

    def toggle_hud(self):
        """切换悬浮窗显示"""
        if self.hud.root.state() == 'withdrawn':
            self.hud.root.deiconify()
        else:
            self.hud.root.withdraw()

    def quit_application(self):
        """退出应用程序"""
        self.stop_all()
        if hasattr(self, 'root') and self.root.winfo_exists():
            self.root.quit()
            self.root.destroy()

    def run_gui(self):
        """运行GUI主循环"""
        # 注册退出处理
        atexit.register(self.stop_all)

        try:
            # 使用隐藏主窗口的主循环
            self.root.mainloop()
        except Exception as e:
            print(f"GUI主循环错误: {e}")
        finally:
            self.stop_all()


def main():
    # 初始化配置管理器
    config_manager = ConfigManager()

    # 创建手势控制系统
    system = SystemGestureControl(config_manager)

    # 在单独线程中运行手势识别
    def run_gesture_recognition():
        # 初始化MediaPipe
        mp_hands = mp.solutions.hands
        hands = mp_hands.Hands(
            static_image_mode=False,
            max_num_hands=1,
            min_detection_confidence=0.7,
            min_tracking_confidence=0.5
        )

        # 尝试打开摄像头
        cap = cv2.VideoCapture(0)
        if not cap.isOpened():
            print("无法打开摄像头")
            return

        print("系统级手势控制系统")
        print("=" * 60)
        print("手势控制映射:")
        for gesture, func in system.gesture_functions.items():
            print(f"  {gesture}: {func}")
        print("=" * 60)
        print("系统托盘图标已创建，右键点击系统托盘图标可打开设置")
        print("=" * 60)
        print("系统正在运行，所有信息将输出到控制台")
        print("=" * 60)

        try:
            while system.running:
                ret, frame = cap.read()
                if not ret:
                    print("无法读取摄像头帧")
                    break

                frame = cv2.flip(frame, 1)
                rgb_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)

                results = hands.process(rgb_frame)

                if results.multi_hand_landmarks:
                    for hand_landmarks in results.multi_hand_landmarks:
                        landmarks = []
                        for landmark in hand_landmarks.landmark:
                            landmarks.extend([landmark.x, landmark.y, landmark.z])
                        landmarks = np.array(landmarks)

                        result = system.process_frame(landmarks)
                        if result:
                            print(f"[{time.strftime('%H:%M:%S')}] {result}")

                # 更新GUI
                system.hud.update()

                # 键盘控制（可选）
                key = cv2.waitKey(1) & 0xFF
                if key == ord('q'):
                    break

        except KeyboardInterrupt:
            print("\n程序被用户中断")
        except Exception as e:
            print(f"程序出错: {str(e)}")
        finally:
            cap.release()
            cv2.destroyAllWindows()

            print("\n" + "=" * 60)
            print(f"程序结束 - 总识别次数: {system.recognition_count}")
            print("=" * 60)

            # 停止系统
            system.stop_all()

    # 启动手势识别线程
    gesture_thread = threading.Thread(target=run_gesture_recognition, daemon=True)
    gesture_thread.start()

    # 在主线程中运行GUI（必须）
    system.run_gui()


if __name__ == "__main__":
    main()